package com.hanlin.backend.service.impl;

import cn.hutool.core.map.MapUtil;
import com.alibaba.druid.sql.visitor.functions.If;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hanlin.backend.common.entity.HlAuthority;
import com.hanlin.backend.common.entity.HlAuthorityUser;
import com.hanlin.backend.dto.AuthorityDto;
import com.hanlin.backend.dto.MetaDto;
import com.hanlin.backend.dto.RoleDto;
import com.hanlin.backend.mapper.HlAuthorityMapper;
import com.hanlin.backend.service.HlAuthorityService;
import com.hanlin.backend.service.HlAuthorityUserService;
import com.hanlin.backend.service.HlRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 权限表 服务实现类
 * </p>
 *
 * @author hl.yuan
 * @since 2021-01-06
 */
@Service
public class HlAuthorityServiceImpl extends ServiceImpl<HlAuthorityMapper, HlAuthority> implements HlAuthorityService {

    @Autowired
    private HlRoleService hlRoleService;

    @Autowired
    private HlAuthorityUserService hlAuthorityUserService;

    @Override
    public List<AuthorityDto> getAuthorityList(Integer userId,Integer roleId) {
        List<Integer> userIds =  new ArrayList<>();
        List<Integer> roleIds =  new ArrayList<>();
        // 用户ID不为空时
        if (userId!=null){
            userIds.add(userId);
            List<RoleDto> userId1 = hlRoleService.getRoleByUserId(userId);
            userId1.forEach(item->{
                roleIds.add(item.getRoleId());
            });
        }
        if (roleId!=null) {
            roleIds.add(roleId);
        }
        // 获取用户或者角色的权限
        List<AuthorityDto> list = getBaseMapper().getAuthorityByIds(userIds, roleIds);
        // 获取所有权限
        List<AuthorityDto> authorityAll = getBaseMapper().getAuthorityAll();
        // 把有权限的菜单给标注出来
        checkAuthority(authorityAll,list);
        List<AuthorityDto> menuData = handlingMenuData(authorityAll);
        return menuData;
    }

    /**
     * 把有权限的菜单给标注出来
     * @param authorityAll  所有的权限
     * @param list 有权限的菜单
     */
    private void checkAuthority(List<AuthorityDto> authorityAll, List<AuthorityDto> list) {
        for (AuthorityDto authority :authorityAll){
            Integer id = authority.getId();
            for (AuthorityDto authorityDto: list) {
                Integer authorityDtoId = authorityDto.getId();
                // 当ID相同时，说明有权限，
                if (id.equals(authorityDtoId)){
                    authority.setChecked(true);
                    break;
                }
            }

        }
    }

    @Override
    public List<AuthorityDto> getAuthorityAll(boolean showRoot) {
        // 查询所有的权限
        List<AuthorityDto> authorityAll = getBaseMapper().getAuthorityAll();
        // 把数据组装成树形结构
        List<AuthorityDto> menuData = handlingMenuData(authorityAll);
        // 是否展示根属性
        if(showRoot){
            AuthorityDto authorityDto = new AuthorityDto();
            authorityDto.setTitle("根目录");
            authorityDto.setId(0);
            authorityDto.setParentId(0);
            authorityDto.setChildren(menuData);
            List<AuthorityDto> authorityDtoList = new ArrayList<>();
            authorityDtoList.add(authorityDto);
            return authorityDtoList;
        }
        return menuData;
    }

    @Override
    public List<AuthorityDto> getUserAuthority(Integer userId) {
        List<Integer> userIds =  new ArrayList<>();
        List<Integer> roleIds =  new ArrayList<>();
        // 用户ID不为空时
        if (userId!=null){
            userIds.add(userId);
            List<RoleDto> userId1 = hlRoleService.getRoleByUserId(userId);
            userId1.forEach(item->{
                roleIds.add(item.getRoleId());
            });
        }
        List<AuthorityDto> list = getBaseMapper().getAuthorityByIds(userIds, roleIds);
        List<AuthorityDto> menuData = handlingMenuData(list);
        return menuData;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAuthority(List<Map> listAuthority, Integer userId, Integer roleId) {
        List<HlAuthorityUser> list = new ArrayList<>();
        saveAuthorityData(listAuthority,userId,roleId,list);
        // 删除之前的菜单权限数据
        hlAuthorityUserService.removeAuthority(userId,roleId);
        // 保存
        hlAuthorityUserService.saveBatch(list);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveMenu(HlAuthority authority) {
        if (authority!=null){
            int id = authority.getId();
            authority.setUpdateTime(new Date());
            if (id==0){
                QueryWrapper wrapper= new QueryWrapper();
                wrapper.eq("parent_id",authority.getParentId());
                List<HlAuthority> list = this.getBaseMapper().selectList(wrapper);
                if (!list.isEmpty()){
                    int maxOrd = list.stream().mapToInt(HlAuthority::getOrd).max().getAsInt();
                    authority.setOrd(maxOrd+1);
                }
            }
            saveOrUpdate(authority);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteMenu(Integer id) {
        // 需要先删除用户与权限表的数据
        if (id!=null){
            // 1. 先根据id，获取子集菜单
            QueryWrapper wrapper = new QueryWrapper();
            wrapper.eq("parent_id",id);

            // 拿到子集
            List<HlAuthority> list = this.getBaseMapper().selectList(wrapper);

            // 迭代子集，得到id集合
            List<Integer> idList = new ArrayList<>();
            list.stream().forEach(item->{
                idList.add(item.getId());
            });
            idList.add(id);

            // 删除用户与权限的数据
            UpdateWrapper updateWrapper = new UpdateWrapper();
            updateWrapper.in("authority_id",idList);
            hlAuthorityUserService.remove(updateWrapper);

            // 在删除菜单数据
            UpdateWrapper updateWrapper1 = new UpdateWrapper();
            updateWrapper1.in("id",idList);
            this.remove(updateWrapper1);
        }

    }

    @Override
    public HlAuthority getMenu(Integer id) {
        // 获取菜单
        if (id!=null){
           return this.getById(id);
        }
        return null;
    }

    /**
     * 递归获取有菜单权限的数据
     * @param listAuthority 权限数据
     * @param userId 用户ID
     * @param roleId 角色ID
     * @param list 需要保存的权限集合
     */
    private void saveAuthorityData(List<Map> listAuthority, Integer userId, Integer roleId, List<HlAuthorityUser> list) {
        for (Map dto: listAuthority){
            Boolean checked = MapUtil.getBool(dto, "checked");
            if (!checked) {
                continue;
            }
            HlAuthorityUser hlAuthorityUser = new HlAuthorityUser();
            Integer authorityId = MapUtil.getInt(dto,"id");
            hlAuthorityUser.setAuthorityId(authorityId);
            if (userId!=null) {
                hlAuthorityUser.setUserId(userId);
            }else if (roleId!=null){
                hlAuthorityUser.setRoleId(roleId);
            }
            list.add(hlAuthorityUser);
            List<Map> children = MapUtil.get(dto,"children",List.class);
            if (children!=null && children.size()>0) {
                // 当有下级数据的时候，就调用自己
                this.saveAuthorityData(children, userId, roleId, list);
            }
        }
    }

    /**
     * 处理菜单数据
     * @param menuList
     * @return
     */
    private List<AuthorityDto> handlingMenuData(List<AuthorityDto> menuList) {
        List<AuthorityDto> authorityDtoList = new ArrayList<>();
        // 循环菜单数据：拿到一级菜单数据
        for (AuthorityDto authorityDto : menuList) {
            int parentId = authorityDto.getParentId();
            // 父级菜单ID为0，说明是一级菜单
            if (0 == parentId) {
                authorityDtoList.add(authorityDto);
            }
            MetaDto metaDto = new MetaDto();
            String title = authorityDto.getTitle();
            String icon = authorityDto.getIcon();
            metaDto.setIcon(icon);
            metaDto.setTitle(title);
            authorityDto.setMeta(metaDto);
            authorityDto.setHidden(authorityDto.getHiddenInt()==1);
        }
        // 循环一级菜单，主要是要循环迭代到下面的子菜单
        for (AuthorityDto authorityDto : authorityDtoList) {
            Integer id = authorityDto.getId();
            // 获取子集菜单数据
            authorityDto.setChildren(getChild(id, menuList));
        }

        return authorityDtoList;
    }

    /**
     * 获取子集菜单数据
     *
     * @param id       父级ID
     * @param menuList 菜单的所有数据
     * @return
     */
    private List<AuthorityDto> getChild(int id, List<AuthorityDto> menuList) {
        // 定义子菜单的集合
        List<AuthorityDto> childList = new ArrayList<>();
        // 循环全部的数据
        for (AuthorityDto menu : menuList) {
            // 遍历所有节点，将父菜单id与传过来的id比较
            int parentId = menu.getParentId();
            // 如果菜单的父级ID和传过来的ID相同，说明是改ID下的菜单，我们就把菜单给放到集合装起来
            if (parentId == id) {
                childList.add(menu);
            }
        }
        // 精华：我们在一次循环子菜单，得到下面的子菜单
        for (AuthorityDto menu : childList) {
            // 得到子集菜单的ID
            int childId = menu.getId();
            // 递归的迭代
            menu.setChildren(getChild(childId, menuList));
        }
        // 递归退出条件，一定要有，不然就是死循环，系统直接GG
        if (childList.size() == 0) {
            // 这里尽量不返回null，防止前端不好处理
            return new ArrayList<>();
        }
        return childList;
    }
}
